package tcp

import (
	"errors"
	"log"
	"net"
	"sync"
	"time"
)

// Pool tcp连接池
type Pool struct {
	RemoteAddr string
	MaxConn    int
	// TODO 控制tcp最大连接时间
	MaxConnTime int

	Mutex sync.Mutex

	activeConns []net.Conn
	idleConns   []net.Conn
}

// MakePool 创建连接池
func MakePool(remoteAddr string, maxConn int, maxConnTime int) *Pool {
	pool := Pool{
		RemoteAddr:  remoteAddr,
		MaxConn:     maxConn,
		MaxConnTime: maxConnTime,
		activeConns: nil,
		idleConns:   nil,
	}
	pool.init()

	return &pool
}

func (p *Pool) init() {
	for i := 0; i < p.MaxConn; i++ {
		conn, err := NewConn(p.RemoteAddr)
		if err != nil {
			log.Fatal(err)
		}
		p.idleConns = append(p.idleConns, conn)
	}
	p.activeConns = []net.Conn{}

	go func() {
		for {
			p.Mutex.Lock()
			totalConn := len(p.idleConns) + len(p.activeConns)
			p.Mutex.Unlock()

			if totalConn < p.MaxConn {
				// TODO 计算需要创建多少个连接，而不是直接创建一个连接
				conn, err := NewConn(p.RemoteAddr)
				if err != nil {
					log.Println(err)
					continue
				}

				p.Mutex.Lock()
				p.idleConns = append(p.idleConns, conn)
				p.Mutex.Unlock()
			}

			time.Sleep(time.Duration(1) * time.Second)
		}
	}()
}

// GetConn 获取连接池
func (p *Pool) GetConn() (net.Conn, error) {
	p.Mutex.Lock()
	defer p.Mutex.Unlock()

	if len(p.idleConns) == 0 {
		err := errors.New("当前没有空闲的连接可用")
		return nil, err
	}

	// TODO 加锁处理，防止并发时同时修改连接池
	conn := p.idleConns[0]
	p.activeConns = append(p.activeConns, conn)
	p.idleConns = p.idleConns[1:]

	log.Printf("获取到连接，当前连接池，空闲：%v，活跃：%v", len(p.idleConns), len(p.activeConns))
	return conn, nil
}

// Release 释放连接
func (p *Pool) Release(conn net.Conn) {
	p.Mutex.Lock()
	defer p.Mutex.Unlock()

	for i, activeConn := range p.activeConns {
		if activeConn.LocalAddr() == conn.LocalAddr() {
			// TODO 加锁处理，防止并发时同时修改连接池

			// 将需要释放的连接放到空闲连接池
			p.idleConns = append(p.idleConns, p.activeConns[i])
			// 将释放的连接从活动连接池中删除，TODO 这里效率比较低
			p.activeConns = append(p.activeConns[:i], p.activeConns[i+1:]...)
		}
	}
	log.Printf("已释放，当前连接池，空闲：%v，活跃：%v", len(p.idleConns), len(p.activeConns))
}
